/*
 * Copyright (C) 2009 University of Washington
 * 
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
 * in compliance with the License. You may obtain a copy of the License at
 * 
 * http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software distributed under the License
 * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
 * or implied. See the License for the specific language governing permissions and limitations under
 * the License.
 */

package org.odk.collect.android.activities;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.util.ArrayList;
import java.util.Scanner;
import java.util.Stack;

import org.odk.collect.android.R;
import org.odk.collect.android.cse481k.CustomGPS;
import org.odk.collect.android.cse481k.NamesDbController;
import org.odk.collect.android.database.FileDbAdapter;
import org.odk.collect.android.utilities.FileUtils;

import android.app.AlertDialog;
import android.app.ListActivity;
import android.content.DialogInterface;
import android.content.Intent;
import android.database.Cursor;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.ListView;
import android.widget.SimpleCursorAdapter;
import android.widget.Toast;

/**
 * Responsible for displaying and deleting all the valid forms in the forms directory.
 * 
 * @author Carl Hartung (carlhartung@gmail.com)
 * @author Yaw Anokwa (yanokwa@gmail.com)
 */
public class FormManagerList extends ListActivity {
    private static String t = "FormManagerList";
    private AlertDialog mAlertDialog;
    private Button mActionButton;
    private Button mGetButton;

    
    private FileDbAdapter mFda = null;
    private SimpleCursorAdapter mInstances;
    private ArrayList<Long> mSelected = new ArrayList<Long>();
    private boolean mRestored = false;
    private final String SELECTED = "selected";

    
    //Added
    private double lat;
    private double lon;
    private static final int CUSTOM_GPS_ID = 1;


    /**
     * Deals with GPS coordinates. If valid GPS coordinates are returned, create new form <br />
     *CSE481K
     */
    protected void onActivityResult(int requestCode, int resultCode, Intent data){
    	if(requestCode == CUSTOM_GPS_ID){    		
    		//Things went well
    		if(resultCode == RESULT_OK){
    			lat = data.getDoubleExtra("Latitude", 0.0);
    			lon = data.getDoubleExtra("Longitude", 0.0);
    			String msg = "Received: lat=" + lat + ", lon=" + lon;    			
    			Log.i("gps", msg);
    			try {
					addNewCustomForm(false);
				} catch (FileNotFoundException e) {	}
				
			//Things did not go well
    		} else {
    			Log.i("gps", "GPS activity went wrong");
    			Toast.makeText(this, "Could not update the form", Toast.LENGTH_LONG).show();
    		}
    	}    		
	}
    	
    	
    
    
    /**
     * Entering File Manager screen will trigger this method to run
     */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        
        //Call CustomGPS, and create new form from its coordinates
        //ID = 1
        Log.i("cr", "StartingAct");  
		Log.i("gpsa", "Accessing GPS");
    	Intent accessGPS = new Intent(this, CustomGPS.class);
    	startActivityForResult(accessGPS, CUSTOM_GPS_ID);
    	
    	/*Some time later onActivityResult method will respond to CustomGPS activity.
    	It will create a new file, but will not call any file management routines.
    	So far everything runs fine*/

        setContentView(R.layout.form_manage_list);
        mGetButton = (Button) findViewById(R.id.get_button);
        mGetButton.setText(getString(R.string.get_forms));
        mGetButton.setOnClickListener(new OnClickListener() {
            @Override
			public void onClick(View v) {
                Intent i = new Intent(getApplicationContext(), FormDownloadList.class);
                startActivity(i);
            }
        });
        
        mActionButton = (Button) findViewById(R.id.delete_button);
        mActionButton.setText(getString(R.string.delete_file));
        mActionButton.setOnClickListener(new OnClickListener() {
            @Override
			public void onClick(View v) {

                if (mSelected.size() > 0) {
                    createDeleteDialog();
                } else {
                    Toast.makeText(getApplicationContext(), R.string.noselect_error,
                        Toast.LENGTH_SHORT).show();
                }
            }
        });
        // buildView takes place in resume
    }
    
    /**
     * Moved from FileDbAdapter.java<br />
     * TEST<br />
     * CSE481K
     */
    public void printToLog(Cursor c) {

    	String rowHeaders = "|| ";
    	for (int i = 0; i < c.getColumnCount(); i++) {
    		rowHeaders = rowHeaders.concat(c.getColumnName(i) + " || ");
    	} 
    	c.moveToFirst();
    	  while (c.isAfterLast() == false) {
    	   String rowResults = "|| ";
    	   for (int i = 0; i < c.getColumnCount(); i++) {
    	    rowResults = rowResults.concat(c.getString(i) + " || ");
    	   }
    	   Log.i("TAG", "Row " + c.getPosition() + ": " + rowResults);


    	   c.moveToNext();
    	  }
    	  Log.i("TAG", "*** Cursor End ***");

    	  c.close();

    	
    }

    /**
     * Moved from FileDbAdapter.java<br />
     * If <strong>failed</strong> flag is high, it will not contact DB, and leave
     * dynamic contents empty.<br />
     * CSE481K
     * 
     * @throws FileNotFoundException
     */
    private synchronized void addNewCustomForm(boolean failed) throws FileNotFoundException{
    	    	
    	Log.i("entry", "Generating");
    	
    	
    	NamesDbController myDb = null;
    	Cursor list = null;
    	File f;
    	
    	//Contacting DB
    	if(!failed){
    		myDb = new NamesDbController(lat, lon);
    		myDb.populate();
	    	list = myDb.fetchNames();
	    	f = (list.getCount() == 0) ? 
	    			new File(FileUtils.FORMS_PATH + "no_entry.xml") : new File(FileUtils.FORMS_PATH + "test.xml");
	    			
	    	Toast.makeText(this, list.getCount() + " Entries nearby", Toast.LENGTH_LONG).show();
    	
    	//No need to contact DB; there is nothing to retrieve
    	} else {
    		f = new File(FileUtils.FORMS_PATH + "no_entry.xml");
    		Toast.makeText(this, "No entries retrieved", Toast.LENGTH_LONG).show();
    	}
    		
    	try{	    	
	    	f.createNewFile();
	    	//At this point we have the list in our hand
	    	
	    	Stack<String> selItem = new Stack<String>();
	    	int items = 0;
   	
	    	FileOutputStream out = new FileOutputStream(f);
	    	
	    	//Header & Static elements
	    	out.write("<h:html xmlns=\"http://www.w3.org/2002/xforms\" ".getBytes());
	    	out.write("        xmlns:h=\"http://www.w3.org/1999/xhtml\" ".getBytes());
	    	out.write("        xmlns:ev=\"http://www.w3.org/2001/xml-events\" ".getBytes());
	    	out.write("        xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" ".getBytes());
	    	out.write("        xmlns:jr=\"http://openrosa.org/javarosa\"> ".getBytes());
	    	out.write("	<h:head> ".getBytes());
	    	out.write("		<h:title>FormPopulatingTest</h:title> ".getBytes());
	    	out.write("		<model> ".getBytes());
	    	out.write("			<itext>".getBytes());
	    	out.write("				<translation lang=\"English\">".getBytes());
	    	out.write("					<text id=\"Choose\"><value>Choose</value></text>".getBytes());
	    	Log.i("item", ""+items);
	    	
	    	//Dynamic itext elements from the list
	    	if(!failed){
		    	while(list.moveToNext()){
		    		String entry = list.getString(list.getColumnIndex("name"));
		    		Log.i("entry", entry);
		    		String output = "					<text id=\"" + entry + "\"><value>" + entry + "</value></text>";
		    		out.write(output.getBytes());
		    		selItem.add(entry);
		    		items++;
		    	}
	    	}
	    	//More static elements
	    	out.write("				</translation>			".getBytes());
	    	out.write("			</itext>".getBytes());
	    	out.write("".getBytes());
	    	out.write("			<instance> ".getBytes());
	    	out.write("				<AnimalLists id=\"AnimalList\">".getBytes());
	    	out.write("					<elm1/>".getBytes());
	    	out.write("				</AnimalLists>".getBytes());
	    	out.write("			</instance> ".getBytes());
	    	out.write("			".getBytes());
	    	out.write("			<bind nodeset=\"/AnimalLists/elm1\" type=\"select1\"/>".getBytes());
	    	out.write("		</model>".getBytes());
	    	out.write("	</h:head> ".getBytes());
	    	out.write("".getBytes());
	    	out.write("	<h:body> ".getBytes());
	    	out.write("		<select1 ref=\"elm1\">".getBytes());
	    	out.write("			<label ref=\"jr:itext('Choose')\"/>".getBytes());

	    	//Dynamic lable elements from itext elements
	    	if(!failed){
		    	for(int i = 0; i < items; i++){
		    		out.write("			<item>".getBytes());	    		
		    		String item = selItem.pop();
		    		String label = "				<label ref=\"jr:itext('" + item + "')\"/>";
		    		out.write(label.getBytes());
		    		String value = "				<value>" + item + "</value>";
			    	out.write(value.getBytes());	
			    	out.write("			</item>".getBytes());
		    	}
	    	}
	    	
	    	//Wrap up
	    	out.write("		</select1>".getBytes());
	    	out.write("	</h:body> ".getBytes());
	    	out.write("</h:html> ".getBytes());
	    	out.close();
	    	myDb.close();
    	} catch (Exception e){}   
    	finally{
    		
    		//For debugging
    		Scanner s = new Scanner(new File(FileUtils.FORMS_PATH + "test.xml"));
    		while(s.hasNextLine())
    			Log.i("xform", s.nextLine());
    		myDb.close();
    	}
    	
    }
    private void refreshView() {
    	if ( mFda == null ) {
        	FileDbAdapter t = new FileDbAdapter();
            t.open();
            mFda = t;
    	}
    	

    	
        // get all mInstances that match the status.
    	mFda.addOrphanForms();
        Cursor c = mFda.fetchFilesByType(FileDbAdapter.TYPE_FORM, null);
        startManagingCursor(c);

        String[] data = new String[] {
                FileDbAdapter.KEY_DISPLAY, FileDbAdapter.KEY_META
        };
        int[] view = new int[] {
                R.id.text1, R.id.text2
        };

        // render total instance view
        mInstances =
            new SimpleCursorAdapter(this, R.layout.two_item_multiple_choice, c, data, view);
        setListAdapter(mInstances);
        getListView().setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);
        getListView().setItemsCanFocus(false);
        mActionButton.setEnabled(!(mSelected.size() == 0));

        // if current activity is being reinitialized due to changing
        // orientation
        // restore all check marks for ones selected
        if (mRestored) {
            ListView ls = getListView();
            for (long id : mSelected) {
                for (int pos = 0; pos < ls.getCount(); pos++) {
                    if (id == ls.getItemIdAtPosition(pos)) {
                        ls.setItemChecked(pos, true);
                        break;
                    }
                }

            }
            mRestored = false;
        }
    }


    /**
     * Create the file delete dialog
     */
    private void createDeleteDialog() {
        mAlertDialog = new AlertDialog.Builder(this).create();
        mAlertDialog.setTitle(getString(R.string.delete_file));
        mAlertDialog.setMessage(getString(R.string.delete_confirm, mSelected.size()));
        DialogInterface.OnClickListener dialogYesNoListener =
            new DialogInterface.OnClickListener() {
                @Override
				public void onClick(DialogInterface dialog, int i) {
                    switch (i) {
                        case DialogInterface.BUTTON1: // delete and
                            deleteSelectedFiles();
                            refreshData();
                            break;
                        case DialogInterface.BUTTON2: // do nothing
                            break;
                    }
                }

            };
        mAlertDialog.setCancelable(false);
        mAlertDialog.setButton(getString(R.string.delete_yes), dialogYesNoListener);
        mAlertDialog.setButton2(getString(R.string.delete_no), dialogYesNoListener);
        mAlertDialog.show();
    }


    private void refreshData() {
        if (!mRestored) {
            mSelected.clear();
        }
        refreshView();
    }


    /**
     * Deletes the selected files.First from the database then from the file system
     */
    private void deleteSelectedFiles() {
        // delete removes the file from the database first
        int deleted = 0;
        for (int i = 0; i < mSelected.size(); i++) {
            Cursor c = mFda.fetchFile(mSelected.get(i));
            String filename = c.getString(c.getColumnIndex(FileDbAdapter.KEY_FILEPATH));
            String hash = c.getString(c.getColumnIndex(FileDbAdapter.KEY_HASH));
            if (mFda.deleteFile(mSelected.get(i))) {
                deleted++;
                Log.i(t, "Deleting file: " + filename);
                File del = new File(filename);
                del.delete();
                
                // also delete formdef.
                String hashname = "/sdcard/odk/.cache/" + hash + ".formdef";
                File fd = new File(hashname);
                fd.delete();
                Log.i(t, "Deleting cache: " + hashname);
            }
            c.close();
        }

        if (deleted > 0) {
            // all deletes were successful
            Toast.makeText(getApplicationContext(), getString(R.string.file_deleted_ok, deleted),
                Toast.LENGTH_SHORT).show();
            refreshData();
            if (mInstances.isEmpty()) {
                finish();
            }
        } else {
            // had some failures
            Toast.makeText(
                getApplicationContext(),
                getString(R.string.file_deleted_error, mSelected.size() - deleted + " of "
                        + mSelected.size()), Toast.LENGTH_LONG).show();
        }

    }


    @Override
    protected void onListItemClick(ListView l, View v, int position, long id) {
        super.onListItemClick(l, v, position, id);

        // get row id from db
        Cursor c = (Cursor) getListAdapter().getItem(position);
        long k = c.getLong(c.getColumnIndex(FileDbAdapter.KEY_ID));

        // add/remove from selected list
        if (mSelected.contains(k))
            mSelected.remove(k);
        else
            mSelected.add(k);

        mActionButton.setEnabled(!(mSelected.size() == 0));

    }


    @Override
    protected void onPause() {
        if (mAlertDialog != null && mAlertDialog.isShowing()) {
            mAlertDialog.dismiss();
        }
        super.onPause();
    }


	@Override
	protected void onDestroy() {
		try {
			if ( mFda != null ) {
				FileDbAdapter t = mFda;
				mFda = null;
				t.close();
			}
		} catch ( Exception e ) {
			e.printStackTrace();
		} finally {
			super.onDestroy();
		}
	}


    @Override
    protected void onResume() {
        // update the list (for returning from the remote manager)
        refreshData();
        super.onResume();
    }


    @Override
    protected void onRestoreInstanceState(Bundle savedInstanceState) {
        super.onRestoreInstanceState(savedInstanceState);
        long[] selectedArray = savedInstanceState.getLongArray(SELECTED);
        for (int i = 0; i < selectedArray.length; i++)
            mSelected.add(selectedArray[i]);
        mRestored = true;
    }


    @Override
    protected void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        long[] selectedArray = new long[mSelected.size()];
        for (int i = 0; i < mSelected.size(); i++)
            selectedArray[i] = mSelected.get(i);
        outState.putLongArray(SELECTED, selectedArray);
    }
}
